home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / master / Examples / Visual / VOpts / reader.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-02-01  |  16.4 KB  |  494 lines

  1. #include "vopts.h"
  2.  
  3. Prototype int get_simple_token(char *buf);
  4. Prototype int get_token(char *buf1, char *buf2, char *buf3);
  5. Prototype struct G_OBJECT **newobj(struct G_OBJECT **objlist, int class, char *buf);
  6. Prototype int parse_config(char * cfname);
  7. Prototype int init_config(char *cfname);
  8. Prototype void close_config(void);
  9.  
  10. /*********************************************************************
  11.  * TOKENS:
  12.  *      TOK_EOF     End of file
  13.  *                  '/''*' '*''/'
  14.  *      TOK_STRING  "string"
  15.  *      TOK_STRING  'string'
  16.  *      TOK_BAR     BAR
  17.  *      TOK_TEXT    TEXT   <string>
  18.  *      TOK_BUTTON  BUTTON <string>
  19.  *      TOK_CHECK   CHECK  <string> <string> <string>
  20.  *      TOK_CYCLE   CYCLE  <string>
  21.  *      TOK_GROUP   GROUP  <string>
  22.  *      TOK_LGROUP  LGROUP <string>
  23.  *      TOK_ITEM    ITEM   <string> <string>
  24.  *      TOK_LIST    LIST   <string> <string> <string>
  25.  *      TOK_MENU    MENU   <string>
  26.  *      TOK_STRING  STRING <string> <string>
  27.  *      TOK_TITLE   TITLE  <string>
  28.  *      TOK_VALUE   VALUE  <string> <string>
  29.  */
  30. #define TOK_ERROR  -1
  31. #define TOK_EOF     0 /* Note ordering of ERROR/EOF is assumed for easy tests below */
  32. #define TOK_STRTOK  1
  33. #define TOK_TOKEN   2
  34. #define TOK_BAR     3
  35. #define TOK_BUTTON  4
  36. #define TOK_CHECK   5
  37. #define TOK_CYCLE   6
  38. #define TOK_GROUP   7
  39. #define TOK_LGROUP  8
  40. #define TOK_ITEM    9
  41. #define TOK_LIST   10
  42. #define TOK_MENU   11
  43. #define TOK_STRING 12
  44. #define TOK_TITLE  13
  45. #define TOK_VALUE  14
  46. #define TOK_TEXT   15
  47.  
  48. struct TOK_LOOK {
  49.    char toktype;   /* Value to return for this token                        */
  50.    char token[6];  /* Note that we only allow 6 characters in a token       */
  51.    char strings;   /* Number of strings that the token takes as an argument */
  52. };
  53.  
  54. struct TOK_LOOK tokens[] = {
  55.    { TOK_BAR,     "BAR   ", 0},
  56.    { TOK_BUTTON,  "BUTTON", 1},
  57.    { TOK_CHECK,   "CHECK ", 3},
  58.    { TOK_CYCLE,   "CYCLE ", 1},
  59.    { TOK_GROUP,   "GROUP ", 1},
  60.    { TOK_LGROUP,  "LGROUP", 1},
  61.    { TOK_ITEM,    "ITEM  ", 3},
  62.    { TOK_LIST,    "LIST  ", 2},
  63.    { TOK_MENU,    "MENU  ", 1},
  64.    { TOK_STRING,  "STRING", 2},
  65.    { TOK_TITLE,   "TITLE ", 1},
  66.    { TOK_VALUE,   "VALUE ", 2},
  67.    { TOK_TEXT,    "TEXT  ", 1},
  68. };
  69. #define MAX_LOOK (sizeof(tokens)/sizeof(struct TOK_LOOK))
  70.  
  71. /*********************************************************************
  72.  * Character classes:
  73.  *  0  CL_EOF    - EOF
  74.  *  1  CL_SLASH  - /
  75.  *  2  CL_STAR   - *
  76.  *  3  CL_DQUOTE - "
  77.  *  4  CL_SQUOTE - '
  78.  *  5  CL_ALPHA  - A-Z a-z
  79.  *  6  CL_BLANK  - ' ' \t \n
  80.  *  7  CL_OTHER  - Anything else
  81.  */
  82. #define CL_EOF     0
  83. #define CL_SLASH   1
  84. #define CL_STAR    2
  85. #define CL_DQUOTE  3
  86. #define CL_SQUOTE  4
  87. #define CL_ALPHA   5
  88. #define CL_BLANK   6
  89. #define CL_OTHER   7
  90. #define MAX_CL     8
  91.  
  92. /*********************************************************************
  93.  * States:
  94.  *  0  ST_SCN - SCAN   - Scanning - Looking for any character - skipping white space
  95.  *  1  ST_GSL - GOTSL  - Found /  - Checking for a matching * to start a comment
  96.  *  2  ST_CMT - CMT    - Comment  - Looking for a * to close a comment
  97.  *  3  ST_GST - GOTST  - Found *  - Checking for a / to close a comment
  98.  *  4  ST_DQT - DQUOTE - String " - Looking for a matching "
  99.  *  5  ST_SQT - SQUOTE - String ' - Looking for a matching '
  100.  *  6  ST_TOK - TOKEN  - Token    - Gathering a keyword token
  101.  */
  102. #define ST_SCN  0
  103. #define ST_GSL  1
  104. #define ST_CMT  2
  105. #define ST_GST  3
  106. #define ST_DQT  4
  107. #define ST_SQT  5
  108. #define ST_TOK  6
  109. #define MAX_ST 7
  110. #define MASK_ST 7
  111.  
  112. /*********************************************************************
  113.  * State Table Transitions:
  114.  *
  115.  *            Character Class
  116.  *            0-EOF   1-/      2-*      3-"      4-'      5-A-Z      6-Blank  7-Other
  117.  *   State
  118.  *   0 SCAN    END    GOTSL   ERROR    DQUOTE   SQUOTE    >TOKEN     SCAN     ERROR
  119.  *   1 GOTSL  ERROR   ERROR   CMT      ERROR    ERROR     ERROR      ERROR    ERROR
  120.  *   2 CMT    ERROR   CMT     GOTST    CMT      CMT       CMT        CMT      CMT
  121.  *   3 GOTST  ERROR   SCAN    CMT      CMT      CMT       CMT        CMT      CMT
  122.  *   4 DQUOTE ERROR   >DQUOTE >DQUOTE  !SCAN    >DQUOTE   >DQUOTE    >DQUOTE  >DQUOTE
  123.  *   5 SQUOTE ERROR   >SQUOTE >SQUOTE  >SQUOTE  !SCAN     >SQUOTE    >SQUOTE  >SQUOTE
  124.  *   6 TOKEN  +END    +GOTSL  ERROR    +DQUOTE  +SQUOTE   >TOKEN     +SCAN    ERROR
  125.  * Note: >     - AC_SAV - Means to append the current character and continue scan
  126.  *       !     - AC_STR - Means to return the current token as a string.
  127.  *       +     - AC_TOK - Means to return the current token as a keyword
  128.  *       ERROR - AC_ERR - Indicates issuing an error
  129.  *       END   - AC_END - Indicates returing the END token.
  130.  */
  131. #define AC_SKP (0<<5) /* Must be zero - the default to do nothing */
  132. #define AC_SAV (1<<5)
  133. #define AC_STR (2<<5)
  134. #define AC_TOK (3<<5)
  135. #define AC_ERR (4<<5)
  136. #define AC_END (5<<5)
  137. #define MASK_AC (7<<5)
  138.  
  139. char statetab[MAX_ST][MAX_CL] =
  140. {
  141. /* 0 ST_SCN  */
  142.    { AC_END,        ST_GSL,         AC_ERR,         ST_DQT,
  143.      ST_SQT,        AC_SAV|ST_TOK,  ST_SCN,         AC_ERR         },
  144. /* 1 ST_GSL */
  145.    { AC_ERR,        AC_ERR,         ST_CMT,         AC_ERR,
  146.      AC_ERR,        AC_ERR,         AC_ERR,         AC_ERR         },
  147. /* 2 ST_CMT   */
  148.    { AC_ERR,        ST_CMT,         ST_GST,         ST_CMT,
  149.      ST_CMT,        ST_CMT,         ST_CMT,         ST_CMT         },
  150. /* 3 ST_GST */
  151.    { AC_ERR,        ST_SCN,         ST_CMT,         ST_CMT,
  152.      ST_CMT,        ST_CMT,         ST_CMT,         ST_CMT         },
  153. /* 4 ST_DQT*/
  154.    { AC_ERR,        AC_SAV|ST_DQT,  AC_SAV|ST_DQT,  AC_STR|ST_SCN,
  155.      AC_SAV|ST_DQT, AC_SAV|ST_DQT,  AC_SAV|ST_DQT,  AC_SAV|ST_DQT  },
  156. /* 5 ST_SQT*/
  157.    { AC_ERR,        AC_SAV|ST_SQT,  AC_SAV|ST_SQT,  AC_SAV|ST_SQT,
  158.      AC_STR|ST_SCN, AC_SAV|ST_SQT,  AC_SAV|ST_SQT,  AC_SAV|ST_SQT  },
  159. /* 6 ST_TOK */
  160.    { AC_TOK|ST_SCN, AC_TOK|ST_GSL,  AC_ERR,         AC_TOK|ST_DQT,
  161.      AC_TOK|ST_SQT, AC_SAV|ST_TOK,  AC_TOK|ST_SCN,  AC_ERR         },
  162. };
  163.  
  164. /*
  165.  * Get a simple token from the file.
  166.  * No parsing of semantics is done at this level.
  167.  */
  168. int get_simple_token(char *buf)
  169. {
  170.    int c;
  171.    int pos;
  172.    int class;
  173.    int action;
  174.  
  175.    pos = 0;
  176.  
  177.    for(;;)
  178.    {
  179.       /* Get the next character from the input file and assign a character class */
  180.       c = getc(global.fp);
  181.       class = CL_OTHER;
  182.       switch(c)
  183.       {
  184.          case EOF:  class = CL_EOF;    break;
  185.          case '/':  class = CL_SLASH;  break;
  186.          case '*':  class = CL_STAR;   break;
  187.          case '"':  class = CL_DQUOTE; break;
  188.          case '\'': class = CL_SQUOTE; break;
  189.          case '\n': global.line++;
  190.          case ' ':
  191.          case '\t':  class = CL_BLANK;  break;
  192.          default:
  193.             if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
  194.                class = CL_ALPHA;
  195.             break;
  196.       }
  197.       /* Run us through the state table to get an action and a new state */
  198.       action = statetab[global.state][class];
  199.       global.state = (action & MASK_ST);
  200.  
  201.       /* Perform the work for the action */
  202.       switch(action & MASK_AC)
  203.       {
  204.          case AC_SAV: if (pos < 64) /* make sure we don't overflow the buffer */
  205.                       {
  206.                          buf[pos++] = c;  /* Save the character */
  207.                          break;
  208.                       }
  209.                       /* Else fall through to the error case */
  210.          case AC_ERR: return(TOK_ERROR);
  211.          case AC_STR: buf[pos] = 0;   /* Null terminate what we gathered */
  212.                       return(TOK_STRTOK);
  213.          case AC_TOK: buf[pos] = 0;
  214.                       return(TOK_TOKEN);
  215.          case AC_END: return(TOK_EOF);
  216.       }
  217.    }
  218. }
  219.  
  220. /*
  221.  * Get the next token and any associated strings.
  222.  */
  223. int get_token(char *buf1,
  224.               char *buf2,
  225.               char *buf3
  226.              )
  227. {
  228.    int i;
  229.    int j;
  230.    int toktype;
  231.    int len;
  232.    char *strs[3];
  233.  
  234.    strs[0] = buf1;
  235.    strs[1] = buf2;
  236.    strs[2] = buf3;
  237.  
  238.    toktype = get_simple_token(buf1);
  239.    if (toktype == TOK_EOF)   return(toktype);
  240.    if (toktype != TOK_TOKEN) return(TOK_ERROR);
  241.  
  242.    /* Go through and uppercase the string */
  243.    /* we KNOW that it consists of only upper/lower case letters */
  244.    len = strlen(buf1);
  245.    if (len > 6) return(TOK_ERROR);
  246.    strcpy(buf1+len, "     "); /* Make sure we blank pad for the memcmp */
  247.    for(i = 0; i < 6; i++)
  248.       if (buf1[i] >= 'a') buf1[i] -= ('a'-'A');
  249.  
  250.    /* Now go through the table and look for a token */
  251.    for (i = 0; i < MAX_LOOK; i++)
  252.       if (!memcmp(buf1, tokens[i].token, 6)) break;
  253.    if (i == MAX_LOOK) return(TOK_ERROR);
  254.  
  255.    /* We have a matching token, get any strings that it wants */
  256.    for(j = 0; j < tokens[i].strings; j++)
  257.    {
  258.       toktype = get_simple_token(strs[j]);
  259.       if (toktype != TOK_STRTOK) return(TOK_ERROR);
  260.    }
  261.  
  262.    /* Everything checks out, let them know what type of token they got */
  263.    return((int)tokens[i].toktype);
  264. }
  265.  
  266. void init_group(struct G_OBJECT *object)
  267. {
  268.    while(object != NULL)
  269.    {
  270.       if (object->next) object->next->prev = object;
  271.       if (object->class == CLASS_CYCLE)
  272.       {
  273.          struct G_VALUE *val;
  274.          struct G_CYCLE *cyc;
  275.  
  276.          cyc = (struct G_CYCLE *)object;
  277.  
  278.          cyc->curval = cyc->values;
  279.          for(val = cyc->curval; val; val = val->next)
  280.          {
  281.             if (cyc->base.next) cyc->base.next->prev = (struct G_OBJECT *)cyc;
  282.          }
  283.       }
  284.       object = object->next;
  285.    }
  286. }
  287. /*
  288.  * Allocate an object structure to hold an entry
  289.  */
  290. static char sizetab[] = { 0,
  291.                           sizeof(struct G_STRING),
  292.                           sizeof(struct G_CYCLE),
  293.                           sizeof(struct G_CHECK),
  294.                           sizeof(struct G_GROUP),
  295.                           sizeof(struct G_LIST)
  296.                          };
  297.  
  298. struct G_OBJECT **newobj(struct G_OBJECT **objlist,
  299.                          int class,
  300.                          char *buf
  301.                         )
  302. {
  303.    struct G_OBJECT *obj;
  304.  
  305.    obj = get_mem(sizetab[class]);
  306.    if (obj == NULL) return(NULL);
  307.  
  308.    if (objlist) *objlist = obj;
  309.    obj->class = class;
  310.    obj->title = savestr(buf);
  311.    return(&obj->next);
  312. }
  313.  
  314. /*
  315.  * Parse the configuration file
  316.  */
  317. int parse_config(char *cfname)
  318. {
  319.    static char buf1[66], buf2[66], buf3[66];
  320.    int toktype;
  321.    int menupos;
  322.    int buttonpos;
  323.    int groupcnt;
  324.    int listflag;
  325.    int textpos;
  326.    struct G_OBJECT **objlist;
  327.    struct G_GROUP  **grplist;
  328.    struct G_VALUE  **valent;
  329.    struct G_GROUP  *group;
  330.  
  331.    grplist = &global.groups;
  332.    objlist = &global.objects;
  333.    valent = NULL;
  334.  
  335.    textpos = menupos = buttonpos = 0;
  336.    groupcnt = 0;
  337. /*
  338.    listflag = 0;
  339. */
  340.    listflag = 1;
  341.    if (init_config(cfname)) return(2);
  342.  
  343.    while((toktype = get_token(buf1, buf2, buf3)) > TOK_EOF)
  344.    {
  345.       switch(toktype)
  346.       {
  347.          case TOK_TEXT:   global.text[textpos] = savestr(buf1);
  348.                           if (textpos++ > MAX_TEXT) goto error;
  349.                           break;
  350.          case TOK_BAR:    global.menuitem[menupos].nm_Type   = MENU_ITEM;
  351.                           global.menuitem[menupos].nm_Label  = NM_BARLABEL;
  352.                           if (menupos++ > MAX_MENU) goto error;
  353.                           break;
  354.          case TOK_MENU:   global.menuitem[menupos].nm_Type   = MENU_MENU;
  355.                           global.menuitem[menupos].nm_Label  = savestr(buf1);
  356.                           if (menupos++ > MAX_MENU) goto error;
  357.                           break;
  358.          case TOK_ITEM:   global.menuitem[menupos].nm_Type   = MENU_ITEM;
  359.                           global.menuitem[menupos].nm_Label  = savestr(buf1);
  360.                           if (buf2[0])
  361.                              global.menuitem[menupos].nm_CommKey = savestr(buf2);
  362.                           global.menuitem[menupos].nm_UserData = savestr(buf3);
  363.                           if (menupos++ > MAX_MENU) goto error;
  364.                           break;
  365.          case TOK_BUTTON: if (buttonpos > MAX_BUTTON) goto error;
  366.                           global.button[buttonpos++].title = savestr(buf1);
  367.                           break;
  368.          case TOK_TITLE:  strcpy(global.wtitle, buf1);
  369.                           break;
  370.          case TOK_LGROUP:
  371.          case TOK_GROUP:  grplist = (struct G_GROUP **)
  372.                                     newobj(
  373.                                            (struct G_OBJECT **)grplist,
  374.                                            CLASS_GROUP, buf1);
  375.                           if (!grplist) return(1);
  376.                           objlist = &(((struct G_GROUP *)grplist)->objects);
  377.                           valent = NULL;
  378. /*
  379.                           (*grplist)->local = toktype == TOK_LGROUP ? 1 : 0;
  380. */
  381.                           ((struct G_GROUP *)grplist)->local
  382.                                             = (toktype == TOK_LGROUP ? 1 : 0);
  383.                           if (groupcnt > global.maxsize) global.maxsize = groupcnt;
  384.                           groupcnt = 2;
  385.                           break;
  386.          case TOK_STRING: objlist = newobj(objlist, CLASS_STRING, buf1);
  387.                           if (!objlist) return(1);
  388.                           groupcnt++;
  389.                           ((struct G_STRING *)objlist)->option = savestr(buf2);
  390.                           valent = NULL;
  391.                           break;
  392.          case TOK_CHECK:  objlist = newobj(objlist, CLASS_CHECK, buf1);
  393.                           if (!objlist) return(1);
  394.                           groupcnt++;
  395.                           ((struct G_CHECK *)objlist)->option0 = savestr(buf2);
  396.                           ((struct G_CHECK *)objlist)->option1 = savestr(buf3);
  397.                           valent = NULL;
  398.                           break;
  399.          case TOK_LIST:   objlist = newobj(objlist, CLASS_LIST, buf1);
  400.                           if (!objlist) return(1);
  401.                           groupcnt += 3;
  402.                           /* lists are just a bit bigger than three lines,   */
  403.                           /* so fudge on the first one, a few more will fit  */
  404. /*
  405.                           listflag = !listflag;
  406. */
  407.                           groupcnt += listflag;
  408. /* Next line replaces trick above to add half ine per list */
  409.                           listflag = 0; 
  410.                           ((struct G_LIST *)objlist)->option = savestr(buf2);
  411.                           valent = NULL;
  412.                           break;
  413.          case TOK_CYCLE:  objlist = newobj(objlist, CLASS_CYCLE, buf1);
  414.                           if (!objlist) return(1);
  415.                           groupcnt++;
  416.                           valent = &((struct G_CYCLE *)objlist)->values;
  417.                           break;
  418.          case TOK_VALUE:  if (valent == NULL) goto error;
  419.                           *valent = get_mem(sizeof(struct G_VALUE));
  420.                           if (!*valent) return(1);
  421.                           (*valent)->next = NULL;
  422.                           (*valent)->title = savestr(buf1);
  423.                           (*valent)->option = savestr(buf2);
  424.                           (*valent)->string = NULL;
  425.                           if (strchr(buf2, '%'))
  426.                           {
  427.                              struct G_STRING *gstr;
  428.  
  429.                              gstr = get_mem(sizeof(struct G_STRING));
  430.                              if (!gstr) return(1);
  431.                              gstr->base.class = CLASS_STRING;
  432.                              (*valent)->string = gstr;
  433.                           }
  434.                           valent = &((*valent)->next);
  435.                           break;
  436.       }
  437.    }
  438.    if (groupcnt > global.maxsize) global.maxsize = groupcnt;
  439.    global.curgroup = global.groups;
  440.    global.menuitem[menupos].nm_Type = MENU_END;
  441.  
  442.    if (toktype == TOK_ERROR)
  443.    {
  444. error:
  445.       sprintf(global.title, "ERROR- %s line %d", cfname, global.line);
  446.       return(1);
  447.    }
  448.    close_config();
  449.  
  450.    /* Now we need to go through the groups and sanitize the pointers as well */
  451.    /* as initialize all the default states                                   */
  452.    init_group(global.objects);
  453.    for(group = global.groups; group != NULL;
  454.        group = (struct G_GROUP *)group->base.next)
  455.    {
  456.       if (group->base.next) group->base.next->prev = (struct G_OBJECT *)group;
  457.       init_group(group->objects);
  458.    }
  459.    return(0);
  460. }
  461.  
  462. /*
  463.  * Open the configuration file and initialize any global data
  464.  */
  465. int init_config(char *cfname)
  466. {
  467.    struct Process *mytask;
  468.    APTR saveptr;
  469.  
  470.    global.state = ST_SCN;
  471.    global.line  = 1;
  472.    mytask = (struct Process *)FindTask(NULL);
  473.    saveptr = mytask->pr_WindowPtr;
  474.    mytask->pr_WindowPtr = (APTR)-1;
  475.    global.fp = fopen(cfname, "r");
  476.    mytask->pr_WindowPtr = saveptr;
  477.    if (global.fp == NULL)
  478.    {
  479.       sprintf(global.title, "ERROR- No %s", cfname);
  480.       return(1);
  481.    }
  482.    return(0);
  483. }
  484.  
  485. /*
  486.  * Close the configuration file and clean up anything else necessary
  487.  */
  488. void close_config()
  489. {
  490.    if (global.fp)
  491.       fclose(global.fp);
  492.    global.fp = NULL;
  493. }
  494.